package lwf.db.manager.worksheet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import net.lwf.factory.WorkSheetFactory;
import net.lwf.hibernate.dao.worksheet.WorkSheetAccessDAO;
import net.lwf.hibernate.dao.worksheet.WorkSheetDAO;
import net.lwf.hibernate.entity.worksheet.WorkSheetInfo;
import net.lwf.hibernate.entity.worksheet.WsType;
import net.lwf.number.util.RandomNumberGenerator;

public class WorkSheetManager {
	
	/**
	 * Checks the worksheet has been accessed or printed before.
	 * If accessed, printing is not allowed, otherwise, system allows for printing.
	 * 
	 * @param userid		User key
	 * @param worksheetId	Worksheet key
	 * 
	 * @return
	 */
	public boolean workSheetAccessed(long userid, long worksheetId) {
		WorkSheetAccessDAO dao = new WorkSheetAccessDAO();
		return dao.workSheetAccessed(userid, worksheetId);
		
	}
	
	public boolean workSheetAccessed(long userid, String wsaccesskey) {
		WorkSheetAccessDAO dao = new WorkSheetAccessDAO();
		return dao.workSheetAccessed(userid, wsaccesskey);
	}
	
	/**
	 * Checks the worksheet has any printing restrictions or not. If the sheet
	 * does not have print restrictions, allows the user to print.
	 * If there are any print restrictions for the worksheet, first checks the user has
	 * accessed/printed the worksheet in a day or not.
	 * 
	 * @param userid		User key
	 * @param worksheetId	Worksheet key
	 * 
	 * @return
	 */	
	public boolean workSheetHasRestrictions(long worksheetId) {
		WorkSheetDAO wsdao = new WorkSheetDAO();
		WorkSheetInfo info = wsdao.getWorkSheetInfo(worksheetId);

		if(info != null && info.getPrintRestrictions() == 0) {
			return false;
		}
		
		return true;
		
	}
	
	public void logWorkSheetAccess(long userKey, long workSheetKey, String wsAccessKey) {
		WorkSheetAccessDAO dao = new WorkSheetAccessDAO();
		dao.create(userKey, workSheetKey, wsAccessKey);
	}
	
	/**
	 * Gets unique displayable worksheets (one per type) for the chosen
	 * grade, subject and topic.
	 * 
	 * @param grade
	 * @param subject
	 * @param topic
	 * 
	 * @return
	 */	

	public Map<WsType, WorkSheetInfo> getUniqueWorkSheetsPerType(String grade, String subject, String topic) {
		Map<WsType, WorkSheetInfo> uniwquews = new HashMap<WsType, WorkSheetInfo>();
		Map<WsType, List<WorkSheetInfo>> worksheetTypes = getWorkSheetTypes(grade, subject, topic);
		Iterator<Entry<WsType, List<WorkSheetInfo>>> iterator = worksheetTypes.entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<WsType, List<WorkSheetInfo>> mapentry = (Map.Entry<WsType, List<WorkSheetInfo>>) iterator.next();
			List<WorkSheetInfo> worksheetspertype = (List<WorkSheetInfo>) mapentry.getValue();
			//Generate random number based on the size
			//FOr now taking the first item from the list
			uniwquews.put(mapentry.getKey(), ((WorkSheetInfo) worksheetspertype.get(0)));
		}
		return uniwquews;
	}
	
	public List<WorkSheetInfo> getUniqueWorkSheetsPerType1(String grade, String subject, String topic) {
		List<WorkSheetInfo> uniwquews = new ArrayList<WorkSheetInfo>();
		Map<WsType, List<WorkSheetInfo>> worksheetTypes = getWorkSheetTypes(grade, subject, topic);
		Iterator<Entry<WsType, List<WorkSheetInfo>>> iterator = worksheetTypes.entrySet().iterator();
		while(iterator.hasNext()) {
			Map.Entry<WsType, List<WorkSheetInfo>> mapentry = (Map.Entry<WsType, List<WorkSheetInfo>>) iterator.next();
			List<WorkSheetInfo> worksheetspertype = (List<WorkSheetInfo>) mapentry.getValue();
			//Generate random number based on the size
			//FOr now taking the first item from the list
			//Set available worksheets under this type
			
			uniwquews.add((WorkSheetInfo) worksheetspertype.get(0));
			
		}
		return uniwquews;
	}

	/**
	 * key is the topic and value is the map of worksheets in which key represents the WsType and 
	 * value is worksheetInfo.
	 * 
	 * @param grade
	 * @param subject
	 * @return
	 */
	public Map<String, Map<WsType, List<WorkSheetInfo>>> getWorkSheetTopics(String grade, String subject) {
		Map<String, Map<WsType, List<WorkSheetInfo>>> worksheets = new HashMap<String, Map<WsType,List<WorkSheetInfo>>>();
		List<WorkSheetInfo> data = WorkSheetFactory.getInstance().getWorkSheetInfo(grade, subject);
		for(WorkSheetInfo info: data) {
			this.processWsTopics(worksheets, info);
		}
		return worksheets;
	}
	
	/**
	 * @param grade
	 * @param subject
	 * @return
	 */
/*	public Map<String, Map<WsType, WorkSheetInfo>> getUniqueWorkSheetByGradeSubject(String grade, String subject) {
		Map<String, Map<WsType, WorkSheetInfo>> worksheets = new HashMap<String, Map<WsType, WorkSheetInfo>>();
		
		Map<String, Map<WsType, List<WorkSheetInfo>>> data = getWorkSheetTopics(grade, subject);
		
		Iterator<Entry<String, Map<WsType, List<WorkSheetInfo>>>> topicsiterator = data.entrySet().iterator();
		//Iterate topics
		while(topicsiterator.hasNext()) {
			Map.Entry<String, Map<WsType, List<WorkSheetInfo>>> mapentrytopic = topicsiterator.next();

			Map<WsType, List<WorkSheetInfo>> value = mapentrytopic.getValue();
			
			Iterator<Entry<WsType, List<WorkSheetInfo>>> iteratorbytype = value.entrySet().iterator();
			//Iterate types
			Map<WsType, WorkSheetInfo> uniquedata = new HashMap<WsType, WorkSheetInfo>();
			while(iteratorbytype.hasNext()) {
				Map.Entry<WsType, List<WorkSheetInfo>> mapentrytype = (Map.Entry<WsType, List<WorkSheetInfo>>) iteratorbytype.next();
				List<WorkSheetInfo> worksheetspertype = (List<WorkSheetInfo>) mapentrytype.getValue();
				int number = RandomNumberGenerator.generate(1, worksheetspertype.size());
				WorkSheetInfo info = worksheetspertype.get(number-1);
				//Set available worksheets under this type
				WsType key = mapentrytype.getKey();
				key.setWorksheetCount(worksheetspertype.size());
				uniquedata.put(mapentrytype.getKey(), info);
			}
			worksheets.put(mapentrytopic.getKey(), uniquedata);
			
		}

		return worksheets;
	}*/
	
	public Map<String, Map<WsType, List<WorkSheetInfo>>> getUniqueWorkSheetByGradeSubject(String grade, String subject) {
		Map<String, Map<WsType, List<WorkSheetInfo>>> worksheets = new HashMap<String, Map<WsType,List<WorkSheetInfo>>>();
		
		Map<String, Map<WsType, List<WorkSheetInfo>>> data = getWorkSheetTopics(grade, subject);
		
		Iterator<Entry<String, Map<WsType, List<WorkSheetInfo>>>> topicsiterator = data.entrySet().iterator();
		//Iterate topics
		while(topicsiterator.hasNext()) {
			Map.Entry<String, Map<WsType, List<WorkSheetInfo>>> mapentrytopic = topicsiterator.next();

			Map<WsType, List<WorkSheetInfo>> value = mapentrytopic.getValue();
			
			Iterator<Entry<WsType, List<WorkSheetInfo>>> iteratorbytype = value.entrySet().iterator();
			//Iterate types
			//Map<WsType, WorkSheetInfo> uniquedata = new HashMap<WsType, WorkSheetInfo>();
			while(iteratorbytype.hasNext()) {
				Map.Entry<WsType, List<WorkSheetInfo>> mapentrytype = (Map.Entry<WsType, List<WorkSheetInfo>>) iteratorbytype.next();
				List<WorkSheetInfo> actual_worksheetspertype =  mapentrytype.getValue();
				List<WorkSheetInfo> worksheetspertype = processWorkSheetType( mapentrytype.getValue());
				if(worksheetspertype.size() == 0) {
					int number = RandomNumberGenerator.generate(1, actual_worksheetspertype.size());
					WorkSheetInfo info = actual_worksheetspertype.get(number-1);
					worksheetspertype = new ArrayList<WorkSheetInfo>();
					worksheetspertype.add(info);
				}
				//Set available worksheets under this type
				WsType key = mapentrytype.getKey();
				key.setWorksheetCount(actual_worksheetspertype.size());
				value.put(key, worksheetspertype);

			}
			worksheets.put(mapentrytopic.getKey(), value);
			
		}

		return worksheets;
	}
	
	private List<WorkSheetInfo> processWorkSheetType(List<WorkSheetInfo> worksheetspertype) {
		List<WorkSheetInfo> processedWs = new ArrayList<WorkSheetInfo>();
		for(WorkSheetInfo info: worksheetspertype) {

			if(info.getDisplayAllInAType() == 0) {
				processedWs.add(info);
			}
		}
		return processedWs;
	}
	
	private void processWsTopics(Map<String, Map<WsType, List<WorkSheetInfo>>> worksheettopics, WorkSheetInfo info) {
		String topic = info.getTopic();
		Map<WsType, List<WorkSheetInfo>> worksheetTypes = null;
		if(worksheettopics.containsKey(topic)) {
			worksheetTypes = (Map<WsType, List<WorkSheetInfo>>) worksheettopics.get(topic);
		}
		else {
			worksheetTypes = new HashMap<WsType, List<WorkSheetInfo>>();
		}
		this.processWsTypes(worksheetTypes, info);
		worksheettopics.put(topic, worksheetTypes);
	}	
	
	
	/**
	 * Gets all worksheets per type that includes several topics for the chosen
	 * grade, subject and topic.
	 * 
	 * @param grade
	 * @param subject
	 * @param topic
	 * 
	 * @return
	 */	

	public Map<WsType, List<WorkSheetInfo>> getWorkSheetTypes(String grade, String subject, String topic) {
		Map<WsType, List<WorkSheetInfo>> worksheetTypes = new HashMap<WsType, List<WorkSheetInfo>>();
		List<WorkSheetInfo> data = WorkSheetFactory.getInstance().getWorkSheetInfo(grade, subject, topic);
		for(WorkSheetInfo info: data) {
			this.processWsTypes(worksheetTypes, info);
		}
		return worksheetTypes;
	}
	
	/**
	 * Gets the count of worksheets available for the given grade and subject.
	 * 
	 * @param grade
	 * @param subject
	 * @return
	 */
	public int getAvailableWorksheetCount(String grade, String subject) {
		return WorkSheetFactory.getInstance().getWorkSheetInfo(grade, subject, null).size();
	}
	
	/**
	 * Gets the count of worksheets available for the given grade.
	 * 
	 * @param grade
	 * @return
	 */
	public int getAvailableWorksheetCount(String grade) {
		return WorkSheetFactory.getInstance().getWorkSheetCount(grade);
	}
	
	/**
	 * Gets the count of worksheets available for the given grade, subject and topic.
	 * 
	 * @param grade
	 * @param subject
	 * @param topic
	 * 
	 * @return
	 */
	public int getAvailableWorksheetCount(String grade, String subject, String topic) {
		return WorkSheetFactory.getInstance().getWorkSheetInfo(grade, subject, topic).size();
	}
	
	private void processWsTypes(Map<WsType, List<WorkSheetInfo>> worksheetTypes, WorkSheetInfo info) {
		WsType type = new WsType();
		type.setType(info.getType());
		type.setTypeDescription(info.getTypeDescription());
		
		List<WorkSheetInfo> data = null;
		if(worksheetTypes.containsKey(type)) {
			data = (List<WorkSheetInfo>) worksheetTypes.get(type);
		}
		else {
			data = new ArrayList<WorkSheetInfo>();
		}
		data.add(info);
		//type.setWorksheetCount(data.size());
		worksheetTypes.put(type, data);
	}

}
